/////////////////////////////////////////////////////////////////////////////
// Name:        fileutils.h
// Purpose:     General-purpose file utility classes and functions
// Author:      Julian Smart
// Modified by:
// Created:     2006-02-09
// RCS-ID:      $Id$
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#ifndef _FILEUTILS_H_
#define _FILEUTILS_H_

class wxInputStream;
class wxOutputStream;
class wxFileHistory;
class wxFileOutputStream;
class wxConfigBase;
class wxZipEntry;
class wxZipInputStream;
class wxProgressDialog;

#include "wx/dir.h"
#include "wx/filename.h"
#include "wx/accel.h"

class wxMenuBar;
class wxFile;
class wxFFile;

enum
{
	// overwrite the destination file if it exists
	FILEUTILS_COPYFILE_OVERWRITE = 1,

	// don't fail if the permissions of the destination file can't be
	// set (after successful copy)
	FILEUTILS_COPYFILE_IGNORE_PERMISSIONS = 2
};

/*!
 * File utilities
 */

class FileUtilities
{
public:

    /// Are the two files identical in content?
    static bool FilesEqual(const wxString& filename1, const wxString& filename2);

    /// Rename first file to second file, copying and deleting original file if
    /// the rename didn't work.
    static bool RenameOrCopyFile(const wxString& filename1, const wxString& filename2);

    /// Get temporary directory
    static wxString GetTempDirectory();

    /// Get document directory
    static wxString GetDocumentDirectory();

    /// Get application data directory
    static wxString GetUserAppDataDirectory(const wxString& appName);

    /// Get suitable download directory
    static wxString GetDownloadDirectory();

    /// Does an extra test in case there's a symbolic link that looks like a file
    static bool DirExists(const wxString& str);

    /// Gets the extension
    static wxString GetExtension(const wxString& filename);

    /// Does the filename have this extension?
    static bool HasExtension(const wxString& filename, const wxString& ext);

    /// Intelligent strip extension: don't strip before a separator,
    /// and don't strip if the 'extension' is different from the passed extension
    /// that we expect - can be comma-separated list.
    static bool StripExtension(wxString& path, const wxString& validExtensions = wxEmptyString);

    /// Ensure extension is present
    static void EnsureExtension(wxString& path, const wxString& requiredExt);

    /// Remove trailing separator
    static bool RemoveTrailingSeparator(wxString& filename);

    /// Make sure the folder exists, otherwise create recursively.
    static bool MkDirRecursively(const wxString& path);

    /// Remove dir recursively
    static bool RemoveDirRecursively(const wxString& path);

    /// Is read-only?
    static bool IsReadOnly(const wxString& filename);

    /// Is this an absolute path?
    static bool IsAbsolutePath(const wxString& path);

    /// Makes an absolute path relative if is under appPath
    static wxString MakeRelative(const wxString& path, const wxString& appPath);

    /// Makes a relative path absolute
    static wxString MakeAbsolute(const wxString& path, const wxString& appPath);

#if defined(__WXMSW__) && !defined(__WXWINCE__)
    /// Creates a shortcut
    static bool CreateShortcut(const wxString& path, const wxString& pathLink, const wxString descr);

    /// Gets the target of a shortcut, or the original file
    static wxString GetShortcutTarget(const wxString& LinkFileName);
#endif

    /// Explores the given folder, under Windows only
    static bool ExploreFolder(const wxString& folder);
    
    /// Append paths without duplicating separator;
    static wxString AppendPaths(const wxString& p1, const wxString& p2, const wxString& sep = wxFILE_SEP_PATH);
    
    /// Does the drive exist?
    static bool DriveExists(const wxString& drive);
    
    /// Get available drives, optionally only the removable ones
    static bool GetAvailableDrives(wxArrayString& paths, wxArrayString& names, bool removableOnly = false);
    
    /// Try to get a volume (drive) from the filename, return true if successful.
    static bool GetVolumeFromFilename(const wxString& filename, wxString& volume);
    
    /// Split volume and filename from path. Returns false if we can't (e.g. wasn't a removeable volume)
    static bool SplitVolume(const wxString& path, wxString& filename, wxString& volume);
    
    /// Find the file substituting this volume. Tests existence first.
    static bool GetFilenameSubstitutingVolume(const wxString& filename, wxString& newFilename, const wxString& newVolume, const wxString& oldVolume,
        bool isFilename = true);
    
    /// Load file history with volume substitution if file not found
    static void FileHistoryLoadWithVolumeSubstitution(wxFileHistory& fileHistory, wxConfigBase& config, const wxString& newVolume, const wxString& oldVolume);
    
    /// Change the Unix file mode
    static bool Chmod(const wxString& path, int mode, bool addMode = false);

    /// Get the Unix file mode. If path is empty, get the default mode for a new file.
    static int GetFileMode(const wxString& path);

    /// Find the given file under the a path and change its mode
    static bool FindAndChmod(const wxString& searchPath, const wxString& filename, int mode, bool addMode = false);

    //// File/stream utility functions
    
    /// Copy a fixed size of data from an input stream to an output stream,
    /// using a buffer to speed it up.
    static bool BufferedCopy(wxInputStream& inStream, wxOutputStream& outStream, size_t size);
    
    /// Copy data from an input stream to an output stream, using a buffer to speed it up.
    /// This version doesn't need a size.
    static bool BufferedCopy(wxInputStream& inStream, wxOutputStream& outStream);
    
    /// Copy file to stream
    static bool CopyFileToStream(wxOutputStream& stream, const wxString& filename);
    
    /// Copy stream to new file
    static bool CopyStreamToFile(wxInputStream& stream, const wxString& filename, size_t size);

    /// Interpret command line as an array
    static wxArrayString SplitCommand(const wxString& command);

    /// Improved wxFileName::SplitPath
    static bool SplitPath(const wxString& fullpath,
                          wxString *path,
                          wxString *name,
                          wxString *ext,
                          wxPathFormat format = wxPATH_NATIVE);
    
    /// Find file/command on PATH, or empty string if not found
    static wxString FindInPath(const wxString& cmd);

    /// Copy files in sourceDir to destDir
    static bool CopyDir(const wxString& sourceDir, const wxString& destDir, bool ifNotExists = true, const wxString& wildcard = wxT("*"), int dirFlags = wxDIR_FILES);

    // Replacement for wxWidgets function that fails if can't set permissions
    static bool CopyFile(const wxString& file1, const wxString& file2, int flags = FILEUTILS_COPYFILE_OVERWRITE | FILEUTILS_COPYFILE_IGNORE_PERMISSIONS);

    // Copy temp filename to target filename prompting if the rename/copy failed.
    // If backupFilename was non-empty, it will first be deleted before the copy if it
    // exists, and the old targetFilename will be copied to backupFilename before
    // targetFilename is overwritten.
    static bool SafelyCopyFile(const wxString& tempFilename, const wxString& targetFilename, const wxString& backupFilename = wxEmptyString, bool leaveBackup = true, wxWindow* parent = NULL);

    // Create stream, prompting for a retry, and if failing, returning false.
    // If it returns false, there is no need for the app to delete the stream:
    // it will have been deleted.
    static bool SafelyCreateFileOutputStream(wxFileOutputStream** stream, const wxString& filename, wxWindow* parent = NULL, const wxString& msg = wxEmptyString, const wxString& title = wxEmptyString);

    // Create file, prompting for a retry, and if failing, returning false.
    // If it returns false, there is no need for the app to delete the file:
    // it will have been deleted.
    static bool SafelyCreateFile(wxFFile** file, const wxString& filename, wxWindow* parent = NULL, const wxString& msg = wxEmptyString, const wxString& title = wxEmptyString);

    static bool SafelyCreateFile(wxFile** file, const wxString& filename, wxWindow* parent = NULL, const wxString& msg = wxEmptyString, const wxString& title = wxEmptyString);

    /// Find the encoding of an HTML file
    static wxString FindHtmlEncoding(const wxString& filename);

    /// Convert to a valid filename (assumes no path separators in filename)
    static wxString MakeValidFilename(const wxString& filename, bool allowSpaces = false);
};

/*!
 * Archive utilities
 */

class ArchiveUtilities
{
public:
        /// Get the zip entry for the given filename
    static wxZipEntry* FindEntry(wxZipInputStream& stream, const wxString& filename);

    /// Copy a fixed size of data from an input stream to an output stream,
    /// using a buffer to speed it up.
    static bool BufferedCopy(wxInputStream& inStream, wxOutputStream& outStream, size_t size);

    /// Copy stream to new file
    static bool CopyStreamToFile(wxInputStream& stream, const wxString& filename, size_t size);

    /// Copy entry to new file
    static bool CopyEntryToFile(wxZipInputStream& stream, const wxString& filename, wxZipEntry* entry);

    /// Unarchive to the given folder, optionally notifying the progress dialog
    static bool UnzipTo(const wxString& archive, const wxString& destinationFolder, wxProgressDialog* progressDialog = NULL);

    /// Unarchive to the given file
    static bool GUnzipTo(const wxString& archive, const wxString& destinationFile);

    /// Unarchive to the given folder, optionally notifying the progress dialog
    static bool UntarTo(const wxString& archive, const wxString& destinationFolder, wxProgressDialog* progressDialog = NULL);

    /// Copy to the given folder, optionally notifying the progress dialog.
    /// relativeTo is the folder to be substracted from each file to determine the relative path for the destination file.
    static bool CopyTo(const wxString& relativeTo, const wxArrayString& files, const wxString& destinationFolder, wxProgressDialog* progressDialog = NULL);

    /// Get the number of entries in the zip file
    static int GetZipEntryCount(const wxString& filename);
};


#endif
 // _FILEUTILS_H_

